ひとりNavigation API Advent Calendar 17日目
https://gyazo.com/133a724fe23c076802eac6857a57a14a
これはひとりNavigation API Advent Calendar 17日目です。
アクセシビリティが気になるのでfocus()に関連することを見ていきましょう
WICGのIssueで言及してそうな部分を見てみる
Focus management for SPA navs · Issue #190 · WICG/navigation-api · GitHub
フォーカスマネジメントの話
SPA ナビゲーションでは、スクリーンリーダーやキーボードユーザーにとってフォーカスが適切に移動しないことがアクセシビリティ上の懸念となっている
MPAではページ遷移時に <body> や autofocus="" 要素へフォーカスがリセットされるが、SPAでは一貫性がない
提案
navigateEvent.transitionWhile() に focusReset オプションを追加する案。
値の候補
"after-transition" → 遷移完了後に <body> または autofocus 要素へフォーカスをリセット
"manual" → 開発者が明示的に focus() を呼び出すまで何もしない
"immediate" → 遷移開始直後にフォーカスをリセット
Issueの中での議論のポイント
SPAではDOMが再構築されるため「同じ要素」に戻すのは困難
IDを使った参照やヒューリスティックによる復元は脆弱で予測不能
開発者が autofocus="" を適切に設定することで、ユーザーが望む要素にフォーカスを移せる
スクリーンリーダーユーザーは <body> よりも見出しやラッパー要素へのフォーカスを好む傾向がある
yamanoku.icon これは画面遷移から考えるNuxtアプリケーションをアクセシブルにする方法のときでも触れた話
結論に近い方向性
デフォルトは"after-transition"が望ましいとされている
より複雑なケースは開発者が"manual"を選び、必要に応じて focus()を制御する
MPAとSPAの挙動をできるだけ対称にすることが目標
Second thoughts on focus management · Issue #202 · WICG/navigation-api · GitHub
次の議論
従来のMPAと同様に「遷移後にフォーカスをリセットする」挙動をデフォルトにする案が提示されている
提案されているデフォルト挙動
focusReset: "after-transition"
遷移完了後に <body> または autofocus 属性を持つ要素へフォーカスをリセット
focusReset: "manual"
フォーカスを自動では変更せず、開発者が制御
問題点・懸念
リセットが有効なケース
Twitterの「Tweet」ボタンを押すと入力欄にフォーカスが移るなど、ユーザー体験として自然
リセットが不適切なケース
Google検索のカルーセルや Twitter のサイドバータブなど、クリックした要素にフォーカスを残す方が直感的
一律に「リセット」をデフォルトにすると、タブUIなどで不便になる
代替案の検討
manualをデフォルトにする案
DOMに要素が残っている場合はフォーカスを保持し、消えた場合のみリセットする簡易ルール
autofocus属性やARIA属性を活用して、より柔軟な制御を可能にする案
開発者に必ずfocusResetを指定させる強制オプション案
結論 (暫定)
現時点ではafter-transitionをデフォルトにする方向で合意
MPAと同じ挙動でユーザーの期待に沿いやすい
開発者がフォーカス管理を意識するきっかけになる
最悪の場合でも、多くのルーターコードがmanualを選ぶだけで大きな問題にはならない
Mismatch between scroll and focus handling · Issue #231 · WICG/navigation-api · GitHub
問題提起
Navigation APIにおいて、スクロール位置とフォーカスの扱いが一致していない
特にpush/replace操作時にスクロールがリセットされない点が議論されている
現状の挙動(2022年時点)
クロスドキュメントナビゲーション(MPA)
スクロール
push/replace でリセット、reload/traverse で復元
フォーカス
push/replace/reload/non-bfcache traverse でリセット
bfcache traverse で復元
SPA
スクロール: push/replace/reload で維持、traverseで復元
フォーカス: push/replace/reload/traverse でリセット
提案
新しいオプションscrollResetを導入し、push/replace 時にスクロールをリセットできるようにする
scrollRestorationをreloadにも適用するよう調整
これにより、同一ドキュメントナビゲーションの挙動をクロスドキュメントナビゲーションに近づける
議論のポイント
フラグメントナビゲーションの扱いが難しい
UI状態をハッシュで管理している場合、リセットが望ましいケースもある
「リセット」と「復元」を一つのオプションにまとめるか、別々に扱うかについて意見が分かれている
結論に近い方向性
scrollReset と scrollRestoration を分けて扱う方が柔軟で分かりやすい
最終的にAPIの互換性に影響するが、クロスドキュメントとSPAの挙動を統一することが目標
yamanoku.icon 現時点ではscrollResetではなくscrollで制御する形になってる